Pages

2009-01-18

newLISP: Twitter Followers/Friends/Common

Here's what I came up with. It does the following:
  1. Builds the HTTP Basic Auth header
  2. Fetches all your followers (100 at a time until no more are found)
  3. Fetches all your friends (again, 100 at a time)
  4. Looks for each of your followers in your friends list
  5. Prints each follower that you haven't marked as a friend
  6. Adds commons (friends who follow you back) to a list
  7. Prints each friend that's not following you
  8. Prints the list of commons
I'm still a newLISP neophyte, and there are some things I know I could have done much more efficiently and "lispy" but this is about the best I could come up with. I also would normally use much longer lines, but I broke it up so that it would show here without breaking the format of the page too badly. Oh, and mega-props to Code2HTML for colorizing this.
#!/usr/bin/newlisp
# Build an HTTP Basic Auth header for get-url.
# Set 'user and 'pass manually
(set 'user "YourTwitterName" 'pass "NotMyPasswd")
(set 'hedr (append "Authorization: Basic "
(base64-enc (append user ":" pass)) "\r\n\r\n"))

# Grabs followers until results list has less than 100
(set 'page 0) (do-until (< numthese 100) (inc page)
(set 'xml (get-url (append
"http://twitter.com/statuses/followers.xml?page="(string page))
5000 hedr))
(set 'these (find-all "<screen_name>(.*)</screen_name>" xml $1))
(cond ((= page 1) (set 'fol these))
((> page 1) (set 'fol (append fol these))))
(set 'numthese (length these))
)

# Grabs friends until results list has less than 100
(set 'page 0) (do-until (< numthese 100) (inc page)
(set 'xml (get-url (append
"http://twitter.com/statuses/friends.xml?page="(string page))
5000 hedr))
(set 'these (find-all "<screen_name>(.*)</screen_name>" xml $1))
(cond ((= page 1) (set 'fri these))
((> page 1) (set 'fri (append fri these))))
(set 'numthese (length these)))

# Iterate followers against friends list
(dolist (follower fol)
(if (nil? (find follower fri))
(print (append follower " is not a friend\r\n"))
# If follower and friend, push to com list
(if (nil? com) (set 'com (list follower))
(push follower com))))

# Iterate friends against followers list
(dolist (friend fri)
(if (nil? (find friend fol))
(print (append friend " is not following\r\n")) (inc notfol)))

# Print list of common (friend & follow)
(dolist (common com)
(print (append common " is following back.\r\n")))
(exit)


Why'd I do this? Why not use Twitter Karma or some other online tool?
  1. I didn't want to enter my username and password into someone else's web app.
  2. I wanted a quick programming project that could take up part of my weekend.
  3. It was fun.

8 comments:

  1. I believe the blogger editor ate the angle brackets < and > Write them as HTML entities: & lt ; and & gt ; (ampersand and semicolon) without the spaces) etc.

    instead of:
    (set 'these (find-all "(.*)" xml $1))

    this:

    (set 'these (find-all "<screen_name>(.*)</screen_name>" xml $1))

    ReplyDelete
  2. Good catch. I didn't see that. It was a pretty late night :P

    It should be fixed in the original post now.

    ReplyDelete
  3. Nice to see you back on the newlisp, ax0n...

    Lutz - you going to get on twitter then? :)

    ReplyDelete
  4. I registered on Twitter with id lutz_mueller but haven't followed up yet posting anything.

    ReplyDelete
  5. After installing LISP how do I use this script? Is it placed in a file I shell to?

    ReplyDelete
  6. I have some VBA code to run in MS Access database but would like to know how to call your Twitter script followers / friends
    from MS Access.
    Totally new to LISP need some kind of wrapper to call your functions.

    Here is some code I have so far in a public module:

    Option Compare Database

    Public Declare Function dllNewlispEval Lib "NewLisp" Alias "newlispEvalStr" (ByVal LExpr As String) As Long
    Private Declare Function LoadLibraryA Lib "kernel32" (ByVal s As String) As Long
    Private Declare Sub FreeLibrary Lib "kernel32" (ByVal h As Long)
    Declare Function lstrLen Lib "kernel32" Alias "lstrlenA" (ByVal lpString As Long) As Long
    Declare Function lstrCpy Lib "kernel32" Alias "lstrcpyA" (ByVal lpString1 As String, ByVal lpString2 As Long) As Long

    Dim NewlispHandle As Long

    Sub Auto_Open()
    LoadNewLISP
    End Sub

    Public Sub LoadNewLISP()
    Dim mylib As String
    Dim hinst As Long
    Dim LibPath As String
    mylib = "C:\Program Files\newlisp\newlisp.dll"
    NewlispHandle = LoadLibraryA(mylib)
    If NewlispHandle = 0 Then
    MsgBox "Can not find C:\Program Files\newlisp\newlisp.dll on this machine."
    End If
    End Sub

    Function NewLisp(LispExpression As String) As Variant
    Dim Result As String
    Dim ResHandle As Long
    Dim ResultCode As Long
    ResHandle = dllNewlispEval(LispExpression)
    Result = Space$(lstrLen(ByVal ResHandle))
    lstrCpy ByVal Result, ByVal ResHandle
    NewLisp = Result
    End Function

    Public Sub Auto_close()
    UnloadNewLISP
    End Sub

    Sub UnloadNewLISP()
    FreeLibrary NewlispHandle
    End Sub

    Public Function CreateLispScript(strUser As String, pw As String) As Variant
    Dim strScript As String
    strScript = "(+ 8 3)"
    CreateLispScript = NewLisp(strScript)
    End Function

    Private Sub Command0_Click()
    Dim str As Variant

    Call LoadNewLISP
    MsgBox CreateLispScript("TwitterName", "TwitterPassword")
    Call Auto_close
    End Sub

    ReplyDelete
  7. Well, if the script is marked executable (mode 755, let's say) on any OS other than Windows, it will use the file path for newlisp in the first line. If newlisp is elsewhere, change the first line of the script to match the path of newlisp, preceded by the hash-bang (#!)

    otherwise, you can always launch it manually with "newlisp twitter.lsp"

    ReplyDelete
  8. I have no idea how to call anything from VBA or Access, as I haven't touched them in more than a decade. I would imagine it would be easier to call the Twitter API directly, rather than using an intermediate language to get the data you want.

    ReplyDelete