need basic help with plugin writing

i actually am using google a LOT! :slight_smile: however i work better if someone gives me an example and then i learn around it.

i’ve been trying to figure it out using google for 4 hours but i keep getting the same error.



i tried this before i asked



year = item.xpath(’./td[@colspan=“2”]/child::text()[position()=2]’).replace(“by”,"")



however, AttributeError: ‘list’ object has no attribute ‘replace’

or also

AttributeError: ‘list’ object has no attribute ‘strip’

i keep getting the same error over n over again…

and many other solutions. i keep getting stuck, especially coz the plugin i’m modding is framework 1, an older version. trust me, i don’t ask unless i’m stuck, i’ve tried all afternoon to get somewhere with this to no avail. :frowning:



Remember that xpath expressions return a list. Other than defining a "for" loop, you will usually need to specify a position in the list to get an item which you can manipulate. Often, you'll wantthe first item which is notated list[0]
For your current problem, I would suggest trying

year = item.xpath('./td[@colspan="2"]/child::text()[position()=2]')[0].replace("by","")

Notice the addition of [0] before .replace

Hope this helps.

thanks mike… that worked!

poop, to reiterate Mike’s point I quote you



<br />
year = item.xpath('./td[@colspan="2"]/child::text()[position()=2]').replace("by","")<br />




gives,



read the error message. It tells you that you're attempting to call replace on a list. You are calling replace on the result of the xpath call hence the result of the xpath call is a list. You keep getting the same error as you keep making that same mistake. The result of an xpath call is a list of elements. You either need to loop over that list or index it using [0] (or [1] etc) to get the item you need. You can also use len() function to find out if the list is empty or not, which is what i used in the pagination code for you.

You really need to understand the concepts here if you want to go further. You can't keep asking people to solve the same problem for you time and time again.

And yes, I realize the strip example I gave you causes the same error (my pseudo code is rarely perfect). But you should be able to fix it now you understand lists being returned from xpath.

Jonny

hey jonny!



sorry for the late “thanks”, but you’ll be happy to know i actually figured it all out by myself before you wrote the latest reply :slight_smile:

i get the concept now. what ‘lists’ are and how you loop and when to use xpath and when python. it’s really starting to make much more sense than at the beginning (remember where i was, 7 pages ago? :))

earlier i actually edited the “thanks mike!” to say “thanks mike and jonny!!” but i must’ve not sent it off…………so again:



**thanks Jonny & Mike!!!

**everything works perfect now! :slight_smile:



the code i wrote is btw, just to show you i’m slowly learning :slight_smile:



  <br />
for item in content.xpath('//tr[@class="group"]'):<br />
    Log(item)<br />
    title = item.xpath('./td[contains(@id,"large_groupid_")]/a/img')[0].get('title')<br />
    Log(title)      <br />
    try: <br />
      drc = item.xpath('./td[@colspan="2"]/a[contains(@href, "artist")]')[0].text<br />
    except IndexError:<br />
      drc = "Unknown"<br />
    Log(drc)<br />
    year = item.xpath('./td[@colspan="2"]/child::text()[position()=2]')[0].strip()<br />
    tokens = year.split()<br />
    actualYearWithBrackets = tokens[0]<br />
    actualYear = actualYearWithBrackets [1:-1]<br />
    Log(actualYear)<br />
    try:<br />
      imdb = item.xpath('./td[@colspan="2"]/div/img')[0].get('src').replace("/static/common/imdb/imdb.","").replace(".png","")<br />
    except IndexError:<br />
      imdb = "None"<br />
    thumb = item.xpath('./td[contains(@id,"large_groupid_")]/a/img')[0].get('src')<br />
    url = item.xpath('./td[contains(@id,"large_groupid_")]/a')[0].get('href')<br />
    Log(url)<br />
    dir.Append(Function(DirectoryItem(PTPTorrent, subtitle=None, title=title, summary="%s, Directed by: %s, IMDB Rating: %s" % (actualYear, drc, imdb), thumb=thumb), thumb=thumb, url=url))<br />
  next = content.xpath('//div[@class="linkbox"]/a/strong[contains(text(), "Next")]/parent::a')<br />
  if len(next) > 0:<br />
    dir.Append(Function(DirectoryItem(PTPnextpage, "More Results", subtitle=None, thumb=None), url=PTPBASE_URL + next[0].get('href')))<br />
  return dir<br />




your token bit worked perfect! and the brackets 0 were the lil deal that made the string editing work :)
furthermore, i found out how to use if/try/except/else rules :)
done now, and we can basically close this thread! thank you all!!! :)

after all…………another tiny question i’m afraid.

meanwhile i’ve become really better at xpath (you’ll see from the code i’ve written), and playing with it using python. it’s fascinating how well it works! :slight_smile: :smiley:

nevertheless, i have a question, not to ask “how do i this or that”, but i’m confused as to why it doesn’t work.



the code:


def PTPTorrent(sender, url, thumb):<br />
  dir = MediaContainer(httpCookies=HTTP.GetCookiesForURL('http://www.youtube.com/'))<br />
  url = url<br />
  pageUrl = PTPBASE_URL + url<br />
  Log("Success!")<br />
  Log(pageUrl)<br />
  webpage = HTTP.Request(pageUrl)<br />
  content=XML.ElementFromString(webpage, isHTML=True)<br />
  for item in content.xpath('//tr[contains(@style,"font-weight:")]'):<br />
    Log(item)<br />
    thumb = content.xpath('.//div[@class="box box_albumart"]/p/img')[0].get('src')<br />
    content2 = XML.ElementFromString(webpage, isHTML=True)<br />
    try:<br />
      title = item.xpath('./td/a')[0].text<br />
      size2 = item.xpath('./td')[1].text <br />
      got = item.xpath('./td')[2].text <br />
      seed = item.xpath('./td')[3].text <br />
      lch = item.xpath('./td')[4].text     <br />
      try: <br />
        free1 = item.xpath('./td/a/strong')[0].text<br />
        if free1 == "None":<br />
          free = ""<br />
        else:<br />
          free1 = free<br />
      except IndexError:<br />
        free = ""<br />
      url2 = item.xpath('./td/span/a')[0].get('href')<br />
    except IndexError:<br />
      title = "***The torrent above has been reported***"<br />
      size2 = "" <br />
      got = "" <br />
      seed = "" <br />
      lch = ""<br />
      url2 = ""<br />
      free = ""<br />
    Log(title)<br />
    for item in content2.xpath('//tr[contains(@class, "pad")]'):<br />
      ratio = item.xpath('.//td/blockquote/blockquote/span')[0].text<br />
    dir.Append(Function(DirectoryItem(AddTorrent, title="%s %s" % (title, free), subtitle=None, summary="Size: %s, Times Downloaded: %s, Seeders: %s, Leechers: %s. 
 If you download this file, your ratio will be: %s" % (size2, got, seed, lch, ratio), thumb=thumb, art=R(ART)), torrentUrl=PTPBASE_URL + url2))<br />
  try:<br />
    video_url = content.xpath('.//object[@height="344"]/embed')[0].get('src').replace("http://www.youtube.com/v/","").replace("&hl=en&fs=1","")<br />
    Log(video_url)<br />
    dir.Append(Function(VideoItem(PlayVideo, title="Play Trailer"),link = video_url))<br />
  except IndexError:<br />
    video_url = "None."<br />
    dir.Append(Function(WebVideoItem(GetYouTubeVideo, title="No Trailer available", subtitle=None, summary=None, duration=None, rating=None, thumb=thumb), video_url=video_url))<br />
  return dir<br />





BIG huh? well the bit that is causing trouble is the "ratio = " the ratio list information is in a totally different part of the same website. but no matter what i've tried so far, it won't loop (i think that's what it's called, isn't it?). it shows me the same ratio information with all the other items, which are nicely browsable though.
the code looks like this: and i do get a result, f.ex. "If you download this file, your ratio will be: 1.32". but it doesn't change with the other items, it just shows the same ratio in all the items of the list, while "Size: %s, Times Downloaded: %s, Seeders: %s, Leechers: %s." works perfectly and gives a nice list.
the html code looks like this f.e.x:


			<tr class="pad hidden" id="torrent_59488"><br />
				<td colspan="5"><br />
					<blockquote><br />
						Uploaded by <a href="user.php?id=4205">oblio</a> <span title="Dec 22 2010, 15:24">2 months, 5 days ago</span><blockquote>If you download this, your ratio will become <span class="r10">1.34</span></blockquote><br />
					</blockquote><br />
…<br />


I’m certainly not a specialist, I’m only writing plugins for two weeks now, but I’ll give it a try :slight_smile:



Why don’t you just write this:


<br />
<br />
    for item in content2.xpath('//tr[contains(@class="pad hidden")]/td/blockquote/'):<br />
      ratio = item.xpath('//blockquote/span')[0].text<br />




I'm not saying what you wrote is wrong, I don't have enough experience yet. I'm only saying what I would try :)
Maybe there's only one 'tr' with different 'block quotes'? This would result in the loop being executed only once.

thanks for this one!

i got rid of the “for item” line and just used this instead:



ratio = item.xpath(‘./following-sibling::tr//blockquote/span[contains(@class,“r”)]’)[0].text

have another lil’ question:



i have the following example html:



<a><br />
  <div><br />
    <span>abc</span><br />
    <span>def</span><br />
    <span>ghi</span><br />




sometimes there's just one "span", sometimes up to four.

how do i make an xpath that will give me the following result:
Abc, Def, Ghi
(i know how to add the capitalisation, but how do i parse all the available spans, even though there can be 1-4 sometimes? i also note the comma i added)
Thanks!!!

You can use join() to glue items from a list together:


<br />
items = HTML.ElementFromURL(url).xpath('//a/div/span')<br />
glued_together = ', '.join(items)

thanks for the hint!

however, my main problem is that the items are returned as a list, and each list item has between 1-4 spans like those described above, if you get me.



kind of like:

for item in content.xpath(’//tr[@class=“group”]’):

bla = HTML.ElementFromURL(url).xpath(’//a/div/span’)

glued_together = ', '.join(bla)



and i want it to join all the span nodes it can find, whether 1 or 4.

You can build up a list and extend that while looping over the outer elements (tr[@class=“group”] in this case):



content = HTML.ElementFromURL(url)<br />
elements = []<br />
for item in content.xpath('//tr[@class="group"]'):<br />
  elements.extend(item.xpath('.//a/div/span'))<br />
<br />
glued_together = ', '.join(elements)<br />


This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.